/*
 *  Arrow
 *
 *  Created by David Giovannini on 1/5/07.
 *  Copyright 2007 Software by Jove. All rights reserved.
 *
 */
 
#ifndef SBJ_NCAllocator_h
#define SBJ_NCAllocator_h

#include <new>

#if !defined(WIN32)
#include <bits/functexcept.h>
#else
#include <xmemory>

namespace std
{
template<class _T1,
	class _T2> inline
	void _Construct(_T1 _FARQ *_Ptr, _T2& _Val)
	{	// construct object at _Ptr with value _Val
	::new ((void _FARQ *)_Ptr) _T1(_Val);
	}
}
#endif

namespace SBJ
{



/*
Class: NCAllocator

For a reason I could not find, std::allocators only support const copy
constructors. Destructive copy constructors are valid. These classes
add support. NC == non-const.
*/

#if !defined(WIN32)
  /**
   *  @brief  An NCAllocator that uses global new, as per [20.4].
   *
   *  This is precisely the allocator defined in the C++ Standard. 
   *	- but a non-const construct added
   *    - all allocation calls operator new
   *    - all deallocation calls operator delete
   */
  template<typename _Tp>
    class NCAllocator
    {
    public:
      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;

      template<typename _Tp1>
        struct rebind
        { typedef NCAllocator<_Tp1> other; };

      NCAllocator() throw() { }

      NCAllocator(const NCAllocator&) throw() { }

      template<typename _Tp1>
        NCAllocator(const NCAllocator<_Tp1>&) throw() { }

      ~NCAllocator() throw() { }

      pointer
      address(reference __x) const { return &__x; }

      const_pointer
      address(const_reference __x) const { return &__x; }

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      pointer
      allocate(size_type __n, const void* = 0)
      { 
	if (__builtin_expect(__n > this->max_size(), false))
	  std::__throw_bad_alloc();

	return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
      }

      // __p is not permitted to be a null pointer.
      void
      deallocate(pointer __p, size_type)
      { ::operator delete(__p); }

      size_type
      max_size() const throw() 
      { return size_t(-1) / sizeof(_Tp); }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] NCAllocator::construct
      void 
      construct(pointer __p, const _Tp& __val) 
      { ::new(__p) _Tp(__val); }

// Infra: added a non-const copy constructor
      void 
      construct(pointer __p, _Tp& __val) 
      { ::new(__p) _Tp(__val); }
	  
      void 
      destroy(pointer __p) { __p->~_Tp(); }
    };

  template<typename _Tp>
    inline bool
    operator==(const NCAllocator<_Tp>&, const NCAllocator<_Tp>&)
    { return true; }
  
  template<typename _Tp>
    inline bool
    operator!=(const NCAllocator<_Tp>&, const NCAllocator<_Tp>&)
    { return false; }
#else

		// TEMPLATE CLASS allocator
template<class _Ty>
	class NCAllocator
		: public std::_Allocator_base<_Ty>
	{	// generic allocator for objects of class _Ty
public:
	typedef std::_Allocator_base<_Ty> _Mybase;
	typedef typename _Mybase::value_type value_type;


	typedef value_type _FARQ *pointer;
	typedef value_type _FARQ& reference;
	typedef const value_type _FARQ *const_pointer;
	typedef const value_type _FARQ& const_reference;

	typedef _SIZT size_type;
	typedef _PDFT difference_type;

	template<class _Other>
		struct rebind
		{	// convert an allocator<_Ty> to an allocator <_Other>
		typedef NCAllocator<_Other> other;
		};

	pointer address(reference _Val) const
		{	// return address of mutable _Val
		return (&_Val);
		}

	const_pointer address(const_reference _Val) const
		{	// return address of nonmutable _Val
		return (&_Val);
		}

	NCAllocator()
		{	// construct default allocator (do nothing)
		}

	NCAllocator(const NCAllocator<_Ty>&)
		{	// construct by copying (do nothing)
		}

	template<class _Other>
		NCAllocator(const NCAllocator<_Other>&)
		{	// construct from a related allocator (do nothing)
		}

	template<class _Other>
		NCAllocator<_Ty>& operator=(const NCAllocator<_Other>&)
		{	// assign from a related allocator (do nothing)
		return (*this);
		}

	void deallocate(pointer _Ptr, size_type)
		{	// deallocate object at _Ptr, ignore size
		::operator delete(_Ptr);
		}

	pointer allocate(size_type _Count)
		{	// allocate array of _Count elements
		return (std::_Allocate(_Count, (pointer)0));
		}

	pointer allocate(size_type _Count, const void _FARQ *)
		{	// allocate array of _Count elements, ignore hint
		return (allocate(_Count));
		}

	void construct(pointer _Ptr, const _Ty& _Val)
		{	// construct object at _Ptr with value _Val
		std::_Construct(_Ptr, _Val);
		}

	void construct(pointer _Ptr, _Ty& _Val)
		{	// construct object at _Ptr with value _Val
		std::_Construct(_Ptr, _Val);
		}

	void destroy(pointer _Ptr)
		{	// destroy object at _Ptr
		std::_Destroy(_Ptr);
		}

	_SIZT max_size() const
		{	// estimate maximum array size
		_SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
		return (0 < _Count ? _Count : 1);
		}
	};

		// allocator TEMPLATE OPERATORS
template<class _Ty,
	class _Other> inline
	bool operator==(const NCAllocator<_Ty>&, const NCAllocator<_Other>&)
	{	// test for allocator equality (always true)
	return (true);
	}

template<class _Ty,
	class _Other> inline
	bool operator!=(const NCAllocator<_Ty>&, const NCAllocator<_Other>&)
	{	// test for allocator inequality (always false)
	return (false);
	}
#endif
}
#endif
